==========================================================================
$                                                                        $
$                           TuToriaL by Tymon                            $
$                                 What:                                  $
$                       CrAckMe #3 by Pixel [GanG]                       $
$                                                                        $
==========================================================================

.AbOuT

Jo all ! Witam w kolejnym nudnum tutorku ktorego mam zaszczyt napisac :)
Dzisiaj zajmiemy sie starawym juz crackme #3 by Pixel [GanG]. Wybralem
akurat tego cm, poniewaz jest on latwy, a jednoczesnie fajny do lamania.
Jednym slowem mowiac ( a wlasciwie trzema :) ) wprost do nauki :).

Co my tu mamy zrobic. Na poczatku standart - s/n i mniejszy standart,
czyli usuniecie nag'a, ale bez patcha (???). No cooz moze sobie poradzimy :)

TOOLS: SoftIce i ... moze IDA ( a wlasciwie W32Dasm ).

.StaRT

Nie bede opisywal w tym tutku wszystkiego od poczatku, bo wiele rzeczy
zostalo juz opisane i szkoda pradu by mowic o tym jeszcze raz. Jednak
don't worry, zajrzyj do textu 'Jak zostac cracks0rem' - tam znajdziesz
opis gdzie szukac potrzebnych informacji. Oki, let's go!

Otwieramy crackme ( uwierz mi, bez tego nie uda ci sie zlamac tego
crackme :) ) i naszym oczom ukazuje sie nag, ktorego oczywiscie musimy
usunac. Oki zostawiamy to na deser. Potem jest juz okienko na s/n.
Wpisujemy szybko jakies liczby, np. 34512 i standardowo:

bpx GetWindowTextA
bpx GetDlgItemTextA

Wciskamy 'Find out' i ... mamy piekne okienko 'Incorrect :))))'.
Fuck, cos nie tak. Oki, moze program pobiera serial jako liczbe,
a nie jako string? Sprobujmy:

bpx GetDlgItemInt       ; prog zwraca pobrana liczbe w eax

Wciskamy buttona i ladujemy w sice. Teraz tylko F11 by zobaczyc
skad zostala wywolana funkcja i widzimy juz kod crackme.
Sprawdzmy jeszcze co siedzi w eax:

? eax
000086D0  0000034512  "" 
^^^^^^^^  ^^^^^^^^^^  ^^^^
  hex        dec      ASCII

Oki, wszystko sie zgadza, wiec idziemy dalej:

017F:004010ED  PUSH      08
017F:004010EF  PUSH      00
017F:004010F1  PUSH      64     
017F:004010F3  PUSH      DWORD PTR [EBP+08]                                     
017F:004010F6  CALL      USER32!GetDlgItemInt                                   
017F:004010FB  MOV       [0040313D],EAX         ; zapisz nasz pobrany s/n                                   
017F:00401100  XCHG      EAX,ECX                ; wymien eax z ecx                                 
017F:00401101  JECXZ     00401170               ; jezeli ecx = 0 skacz                                
017F:00401103  XOR       EAX,EAX                ; zeruj eax
017F:00401105  CPUID                            ; ???

Oki, instrukcja JECXZ sprawdza szy ecx = 0 i jezeli to prawda skacze
do 401170. Zgadnij co tam jest? Jezeli nie wiesz to zadzwon do Davida
Harkleya ( to chyba tak sie pisze? ) lub nacisnij F10 w odpowiednim 
miejscu :) Ciekawa jest tez instrukcja CPUID. Co ona robi? Pozwole sobie
tu przytoczyc text Patryka Kobierskiego:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     xor eax,eax
     cpuid
     mov dword ptr VendorID,ebx
     mov dword ptr VendorID+4,edx
     mov dword ptr VendorID+8,ecx

Wykorzystane tu zostao dziaanie rozkazu CPUID gdy rejestr EAX jest
wyzerowany. Zwraca on wtedy w rejestrach EBX, EDX i ECX kolejne czci
12-bajtowego napisu w kodach ASCII. Przykadowo, dla procesorw firmy
Intel rejestry te bd zawiera nastpujce dane: 

     EBX - 756E6547h - "uneG"
     EDX - 49656E69h - "Ieni"
     ECX - 6C65746Eh - "letn"

co po wpisaniu do tablicy "VendorID" da napis "GenuineIntel". Po
przetestowaniu programu na rnych komputerach, mona pokusi
si o stworzenie tabelki: 

_________________________________________________
|    VendorID   |  Firma   |      Przykady      |
|---------------|----------|---------------------| 
|"GenuineIntel" |Intel     |i486DX4, i486SX2, P5 |
|"CyrixInstead" |Cyrix     |M1, M2               |
|"AuthenticAMD" |AMD       |K5, K6               |
|"UMC UMC UMC " |UMC       |U5S, U5SD            |
--------------------------------------------------

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

So jak widzisz CPUID zwraca w ebx-edx-ecx typ posiadnego przez nas
procesorka. U mnie powstal wiec napis: GenuineIntel. Oki idziemy dalej:

017F:00401107  MOV       [00403158],EBX    ; zapisz VendorID procka        
017F:0040110D  MOV       [0040315C],EDX    ; -"- 
017F:00401113  MOV       [00403160],ECX    ; -"-
017F:00401119  XOR       EAX,EAX           ; zerowanie eax
017F:0040111B  XOR       ECX,ECX           ; zerowanie ecx
017F:0040111D  XOR       EDX,EDX           ; zerowanie edx

Oki, tu prawie nic ciekawego sie nie dzialo. Dalej: 

017F:0040111F  LEA       EBX,[00403158]    ; offset VendorID do ebx
017F:00401125  XLAT                        ; laduj kolejne znaki VendorID do eax
017F:00401126  XOR       EAX,000001CC      ; znak xor eax
017F:0040112B  SHL       EAX,10            ; wynik shl 10
017F:0040112E  ADD       EDX,EAX           ; i dodaj do edx
017F:00401130  INC       ECX               ; inkrementuj ecx
017F:00401131  MOV       EAX,ECX           ; eax = ecx
017F:00401133  CMP       EAX,0C            ; sprawdz czy przeobione zostaly
017F:00401136  JNZ       00401125          ; wszystkie znaki VendorID
                                    
Jak pewnie sie skaples ( -as :) ) ta czesc kodu tworzy pewien unikalny numer
na podstawie VendorID, ktory znajduje sie w edx. Z tego wynika, ze dla kazdego
typu procesora powsatanie inna liczba. U mnie jest to 13A70000h, czyli dla kazdego
procesora Intela powstanie taki wlasnie numer. Oki warta wytlumaczenia jest
instrukcja XLAT:

Opis:
Rozkaz aduje do rejestru AL zawarto elementu tablicy. Przed wykonaniem 
rozkazu tablica jest wskazywana przez DS:(E)BX, a numer elementu znajduje
si w AL. Mona to zapisa AL:=DS[byte ptr BX+AL] 

                prosto ze strony BinBoy'a :)

Czyli XLAT laduje znak z tablicy [ebx+ax]. Z tego wynika, ze w ebx musi byc offsetem
danej tablicy, a ax to lumer znaku do pobrania.

Oki, idziemy dalej:

017F:00401138  MOV       EAX,EDX                 ; powstaly numer idzie do eax
017F:0040113A  MOVSX     EBX,BYTE PTR [00403145] ; ladowanie znaku spod 403145
017F:00401141  MUL       EBX                     ; nasz_numer*pobrany_znak
017F:00401143  XCHG      EAX,ECX                 ; wymien eax z ecx
017F:00401144  JECXZ     00401170                ; i jezeli ecx = 0 to bye!

Fuck, co sie tu dzieje? Nasz utworzony numer idzie do eax. Potem pobierany
jest znak spod [00403145] i mnozony przez nasza liczbe. Nastepnie jest
sprawdzenie czy wynik mnozenia rowna sie zero i jezeli tak to 'Inco...'
Zobaczmy co jest zatem pod [00403145].

d 00403145

i co? Nic? Tu pobierane jest 0. A jak wiadomo dowolna_liczba*0 = 0. To jak to
rozwiazac? Przeciez nic nie wpisywalismy pod [00403145]. Tu ladujemy proga
do IDA lub Wdasma ( polecam to pierwsze ) i troche przewijania... Juz wiem
cos sie dzieje na poczatku. Dobra, zaraz to sobie zobaczymy, jednak
zobacz jeszcze co sie dzieje dalej w sprawdzaniu s/n:

017F:00401146  XCHG      EAX,ECX        
017F:00401147  MOVSX     EBX,BYTE PTR [00403146]
017F:0040114E  MUL       EBX            
017F:00401150  XCHG      EAX,ECX        
017F:00401151  JECXZ     00401170

Jak widzisz dzieje si to samo, tylko, ze z tablica [00403146]. Cooz
ladujemy proga z SoftIce loadera by przyjzec sie temu blizej:

017F:00401000  PUSH      00
017F:00401002  CALL      KERNEL32!GetModuleHandleA      ; standardowo
017F:00401007  MOV       [0040314C],EAX                 ; zapisz hinstance
017F:0040100C  CALL      004011A8                       ; a tu jest cos ciekawego :)
017F:00401011  LEA       EAX,[00403141]                 ; bo w tym wlasnie call'u
017F:00401017  PUSH      EAX                            ; zostaje odszyfrowany string
017F:00401018  PUSH      00004E33                       ; Software\NuMega\SoftICE ...
017F:0040101D  PUSH      00             
017F:0040101F  PUSH      00403020       
017F:00401024  PUSH      80000002       
017F:00401029  CALL      ADVAPI32!RegOpenKeyExA         ; ... ktory zostaje tu wlasnie
017F:0040102E  OR        EAX,EAX                        ; otwarty
017F:00401030  JNZ       0040103B                       ; i jezeli istnieje
017F:00401032  MOV       BYTE PTR [00403146],00         ; to zapisz 0 pod 00403146
017F:00401039  JMP       00401048                       ; i przejdz dalej
017F:0040103B  PUSH      EAX            
017F:0040103C  CALL      ADVAPI32!RegCloseKey           
017F:00401041  MOV       BYTE PTR [00403146],01         ; a jezeli nie istnieje taki klucz
                                                        ; to zapisz 1 pod 00403146

Hmm... Chyba cos znalezlismy :) Jak wiemy pod 00403146 nie moze byc 0,
czyli klucz Software\NuMega\SoftICE nie moze istniec :) Chyba wiesz co
masz teraz zrobic. Zamien go na, np. Software\Nu3Mega\SoftICE i juz mamy
zalatwiony ten ANTY-SI. Oki, jeszcze zostala tablica 00403145.

017F:00401048  CALL      004011F0
017F:0040104D  NOP  

Ciekawy ten call. Moze go odwiedzimy ? :)

017F:004011F0  CALL      KERNEL32!GetCommandLineA   ; pobirz CommandLine
017F:004011F5  XOR       ECX,ECX                    ; zerowanie
017F:004011F7  XOR       EDX,EDX                    ; rejestrow
017F:004011F9  CMP       BYTE PTR [EAX+ECX],22      ; sprawdz czy pierwszy znak
017F:004011FD  JNZ       0040126F                   ; CommandLine to ". Jezeli nie to bye!
017F:004011FF  INC       ECX                        ; jezeli sie zgadza to inc ecx
017F:00401200  CMP       BYTE PTR [EAX+ECX],22      ; i sprawdz gdzie jest kolejny "
017F:00401204  JNZ       004011FF               

Co my tu mamy. CommandLine to nic innego jak sciezka naszego programy.
CrackMe sprawdza, czy pierwszy znak naszej sciezki to '"' i jezeli
sie nie zgadza to wpisuje 0 do naszej tablicy 00403145. Teraz troche
pomyslmy ... Tak! By na poczatku CommandLine bylo '"' musimy uruchomic
go z konsoli ( spod DOS'a w windows lub z 'Otworz' w menu start ).
Oki pierwszy czek sprawdzony, ale chyba Pixel postaral sie by to az takie
latwe to nie bylo :)

017F:00401206  ADD       ECX,02                     ; 2 miejca do przodu
017F:00401209  MOV       EDX,ECX                    ; edx = ecx
017F:0040120B  INC       EDX                        ; edx = edx+1
017F:0040120C  CMP       BYTE PTR [EAX+EDX],00      ; sprawdz czy 0
017F:00401210  JNZ       0040120B                   ; jezeli nie to sprawdzaj dalej
017F:00401212  SUB       EDX,ECX        ; dlugosc sciezki_z_paramertrem - dlug_sciezki

Co tu jest robione? Sprawdzana jest dlugosc tego co jest po koncu
sciezki. Co to znaczy? Sprawdzana jest dlugosc parametru z jakim
uruchomiony jest prog. U mnie ( poniewaz nie mialem parametru )
procka liczy jakies smieci z pamieci.

017F:00401214  ADD       EAX,ECX                    ; teraz eax wskazuje tylko na parametr
017F:00401216  MOV       [00403147],DL              ; zapisuje dlugosc parametru
017F:0040121C  INC       EDX                        ; edx =edx+1
017F:0040121D  PUSH      EDX                        ; ilosc danych do skopiowania
017F:0040121E  PUSH      EAX                        ; miejsce zrodlowe
017F:0040121F  PUSH      00403165                   ; miejsce docelowe
017F:00401224  CALL      KERNEL32!lstrcpyn          ; kopiuj
017F:00401229  CMP       BYTE PTR [00403147],08     ; sprawdz czy dlug_parametru = 8
017F:00401230  JNZ       0040126F                   ; jezeli nie to zapisz 0 w tablicy

Tutaj jest nic innego jak kopjowanie parametru z jakim zostal uruchomiony
crackme's w miejsce 00403165. Potem jest sprawdzenie czy slugosc parametru
rowna sie 8 i jezeli nie to zapisuje 0 do naszej tablicy [00403145].
Oki, no problem. Uruchamiamy cm z jakims 8 bajtowym parametrem ( 8 znakow :) ).

017F:00401232  XOR       EAX,EAX
017F:00401234  MOVSX     EAX,BYTE PTR [ECX+00403165] ; laduje do eax znak z param.            
017F:0040123B  IMUL      EBX,EAX,03                  ; ebx = znak*3
017F:0040123E  XOR       BX,00C0                     ; wynik xor 0C0h
017F:00401243  MOV       [ECX+0040316D],BL           ; zapisz przekonwertowany znak
017F:00401249  INC       ECX                         ; ecx= ecx+1
017F:0040124A  CMP       ECX,07                      ; i tak wszystkie znaki
017F:0040124D  JBE       00401234

Tutaj jest nic innego jak kodowanie naszego parametru. Kazdy
znak jest przerabiany wedlug schematu:

przerobiony_znak = (znak*3) xor 0C0h

Potem ten zakodowany znak jest wstawiany do [0040316D].

017F:0040124F  CALL      00401187                ; tutaj jest odkodowanie pewnego stringu
                                                 ; jezeli jestes ciekawy jak, to sobie looknij  
017F:00401254  PUSH      0040316D                ; na stos nasz zakodowany parametr
017F:00401259  PUSH      00403038                ; na stos odkodowany string
017F:0040125E  CALL      KERNEL32!lstrcmp        ; porownaj
017F:00401263  OR        EAX,EAX
017F:00401265  JNZ       0040126F                ; jezeli nie rowne to wpisz do tab 0
017F:00401267  MOV       BYTE PTR [00403145],01  ; a jezeli rowne to 1
017F:0040126E  RET
017F:0040126F  MOV       BYTE PTR [00403145],00
017F:00401276  RET

He ... Jestesmy juz przy koncu sprawdzania. Aby w naszej tablicy [00403145]
byla jedynka, musimy byc spelniony warunek:

 Zakodowany(Parametr) = Odkodowany(string)

Nic prostrzego :) Sam spobuj to zrobic. Jak sie nie uda to read dalej.

No jak pewnie sie domyslasz to musimy odkodowac nasz parametr, ale
podstawiajac pod niego rozkodowany string. Skoro rozkodowany string
to: _SP0k0!_ to nasza praca ogranicza sie do odwrocenia kolejnosci
instrukcji i urzycia ich przeciwnych odpowiednikow. So...

jak przerobiony_znak = (znak*3) xor 0C0h

to  znak = (przerobiony_znak xor 0C0h) / 3

Oczywiscie teraz przerobiony_znak = odpowiedni_znak_poprawnego_stringa :)
A i jeszcze jedno, instrukcja odwrotna do xor jest ... xor :)

'_'  xor 0C0h  / 3  =   '5'
'S'  xor 0C0h  / 3  =   '1'
'P'  xor 0C0h  / 3  =   '0'
'0'  xor 0C0h  / 3  =   'P'
'k'  xor 0C0h  / 3  =   '9'
'0'  xor 0C0h  / 3  =   'P'
'!'  xor 0C0h  / 3  =   'K'
'_'  xor 0C0h  / 3  =   '5'

Wiec nasz prawidlowy parametr to 510P9PK5. Uruchamiamy z nim crackme. Oczywiscie
Do naszej tablicy zostala wpisana jedynka, ale jeszcze cos ... Widzieliscie
moze gdzies to okienko co mialo byc usuniete ? :)

Oki wracamy do lamania s/n. Tablice mamy z glowy, wiec idziemy dalej:

017F:00401153  CMP       [0040313D],ECX      ; hmm.. jakies dziwne porownanie :) 
017F:00401159  JNZ       00401170

No dobra. Sprawdzamy co jest pod [0040313D].

d 0040313D

Wow! To nic innego jak nasz s/n tylko w odwrotnej formie i w hex. Jak nie
wierzysz to sprawdz :). Oki, ale co jest w ecx. No tak to nic innego
jak wartosc wygenerowana na podstawie VendorID, czyli typie naszego procka.
Oczywiscie jezeli te dwie wartosci sa rowne to mamy good key :)

Sprawdzmy jeszcze ecx:

:? ecx                                                                          
13A70000  0329711616  "  "

My oczywiscie wpisujemy wartosc dziesietna, czyli:

                GOOD KEY: 329711616 [ dla intela ]
                PARAMETR: 510P9PK5  [ dla kazdego :)]

Latwo wyliczyc takze inne s/n dla innych prockow:

                [AMD]           S/n:328138752
                [Cyrix]         S/n:334954496
                [UMC]           S/n:331284480

.eNd

To juz jest koniec... Nie ma juz nic... Jestescie wolni... mozecie ... jeszcze
przeczytac Greetz'y :) Oki. Tak podsumujac to bylo to bardzo latwe crackme :)
Na prawde. Teraz moze Ci sie wydawac, ze tyle obliczen itd., ale za kilka miechow
zrozumiesz, ze to crackme to 15 min :) ( oczywiscie to dotyczy tylko newbies,
starszy wyjadacze wiedza o co chodzi :) ). Ja jak uczylem sie z tutkow mNICH'a
myslalem, ze te crackme ktore opisal, to sa srednio - trudne i czas na ich 
zlamanie to min. 1h. Teraz wiem, ze 10 min. to wystarczajacy czas by zrobic 
do nich kg :). Oczywiscie jak masz jakies pytania, za duzy dom, kasa w kieszeni
Cie uwiera to mailto:Tymon_crk@wp.pl :). Pozdrowienia dla wszystkich ludzi
lubiacych ostrzejsze granie i dla wszystkich lubiacych karmic swoje uszy
Acid Drinkers, KN, Marilyn'em Manson'em, Therion'em itd. See ya!

.LinKZ

www.cracking.pl       // texty na karzdy temat
www.zoomek.prv.pl     // strona zoomka, najlepsza jezeli chodzi o asm. Znajdziesz
                      // tu opisy wielu sztuczek ANTY-SI
www.ctrl-d.prv.pl     // strona Barta, crack news
www.crackmes.prv.pl   // najlepsza strona dla praktyki. Siagaj crackmes i tutki, a dosc
                      // szybko zrozumiesz o co biega.
crackmes.host.sk      // next strona z cm, tylko wieksza i po angilesku
www.witeg.prv.pl      // swietna strona crackme lamacza. Crypto w asm.
rp2k.host.sk          // he .. he .. REVOLUTiON PROJECT

.tHaNX t0:

     ged_ * hauer * Kwasek * snatch * ToMKoL * ved * veneta * zakonna
     all from AAoCG & HTBTeam
